package com.broada.apm.service.impl;

import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellRangeAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.broada.apm.ajax.PerformanceResult;
import com.broada.apm.ajax.Result;
import com.broada.apm.ajax.TransactionResult;
import com.broada.apm.base.BaseService;
import com.broada.apm.entity.OrderClass;
import com.broada.apm.entity.Service;
import com.broada.apm.entity.TradePerformance;
import com.broada.apm.entity.TransactionChannel;
import com.broada.apm.entity.TransactionType;
import com.broada.apm.model.ApplicationSystem;
import com.broada.apm.model.PagingList;
import com.broada.apm.model.PerformanceView;
import com.broada.apm.model.Resource;
import com.broada.apm.service.TransactionService;
import com.broada.apm.utils.ExceptionUtils;

public class TransactionServiceImpl extends BaseService implements TransactionService {
	private final static Logger logger = LoggerFactory.getLogger(TransactionServiceImpl.class);

	@Override
	public PerformanceResult getTradesPerformancesTotal(String appId, String nodeId, String vsite, String orderBy,
			boolean desc, String keyWord, String tradeIp, String tradeProto, long startDate, long endDate, int top, int pageSize, int pageIndex) {
		PerformanceResult result = new PerformanceResult();
		if ("NaN".equals(endDate) || "NaN".equals(startDate)) {
			result.setFailMessage("查询时间错误");
			return result;
		}
		if (endDate == 0)
			endDate = System.currentTimeMillis();
		if (startDate == 0)
			startDate = endDate - 60 * 60 * 1000;
		List<PerformanceView> perfs = tradePerformanceLogic.getTradesPerformancesTotal(appId, nodeId, vsite, orderBy,
				desc, keyWord, tradeIp, tradeProto, new Date(startDate), new Date(endDate), top);

		List<TradePerformance> tradePerfs = new ArrayList<TradePerformance>();
		List<String> resIds = new ArrayList<String>();
		for (PerformanceView performance : perfs) {
			resIds.add(performance.getResourceId());
		}
		Map<String, Resource> map = new HashMap<String, Resource>();
		List<Resource> resourceList = resLogic.queryResourcesByIds(resIds);
		if (resourceList != null && !resourceList.isEmpty()) {
			for (Resource res : resourceList) {
				map.put(res.getId(), res);
			}
		}
		for (PerformanceView performance : perfs) {
			Resource res = map.get(performance.getResourceId());
			String uri = null;
			String ip = null;
			int protocol = 1;
			if (res != null) {
				Service service = null;
				if (performance.getServiceId().contains("-")) {
					service = serverLogic.queryServiceById(performance.getServiceId());
				} else {
					service = serverLogic.queryDisServiceById(performance.getServiceId());
				}
				if (service != null) {
					ip = service.getIp();
					protocol = service.getProtocol();
				}
				uri = res.getUri();
			}
			tradePerfs.add(new TradePerformance(null, performance.getResourceId(), uri, ip, protocol, performance));
		}
		
		result.pagingHandle(pageSize > 0 ? pageSize : 10, pageIndex, tradePerfs);
		return result;
	}

	@Override
	public PerformanceResult tradeTracking(String appId,String transactionFlag,String agentId, String keyWord,
			String transactionType, String transactionChannel, long startDate, long endDate, String orderBy,
			boolean desc, int pageSize, int pageIndex,String tracking) {
		PerformanceResult result = new PerformanceResult();
		if ("NaN".equals(endDate) || "NaN".equals(startDate)) {
			result.setFailMessage("查询时间错误");
			return result;
		}
		if (StringUtils.isBlank(appId)) {
			result.setFailMessage("参数错误");
			return result;
		}
		if (endDate == 0)
			endDate = System.currentTimeMillis();
		if (startDate == 0)
			startDate = endDate - 60 * 60 * 1000;
		PagingList<PerformanceView> perfs = new PagingList<PerformanceView>();
		try {
			//TODO 未来关联agentId
			List<Service> serviceList = serverLogic.queryServiceByAppId(appId);
			Map<String, Service> map = new HashMap<String, Service>();
			for (Service service : serviceList) {
				map.put(service.getId(), service);
			}
			// 交易跟踪
			perfs = tradePerformanceLogic.getTrackingTradesPerformances(appId, agentId,
					keyWord, transactionType, transactionChannel, startDate, endDate, pageIndex, pageSize > 0 ? pageSize : 10, orderBy, desc, transactionFlag);
			
			result.setTotalPage(perfs.getTotalPages());
			result.setPageSize(pageSize);
			result.setPageIndex(pageIndex);
			result.setTotal((int) perfs.getTotalRecords());
			result.put("result", perfs.getData());
			if (result.get("result") != null) {
				@SuppressWarnings("unchecked")
				List<PerformanceView> list = (List<PerformanceView>) result.get("result");
				for (PerformanceView perf : list) {
					if (perf.get("startTime") == null || StringUtils.isBlank(perf.get("startTime").toString().trim())) {
						continue;
					}
					if (StringUtils.isNotBlank(tracking)) {
						Service service = serverLogic.queryServiceById(perf.getServiceId());
						perf.put("serviceIconUrl", service != null ? service.getIconUrl() : null);
					}
					try {
						perf.put("startTime", perf.get("startTimeMillion"));
					} catch (Exception e) {
					}
					if (perf.get("responseCode") == null || StringUtils.isBlank(perf.get("responseCode").toString().trim())) {
						perf.put("responseCode", perf.get("responseCodeString"));
					}
					
				}
			}
		} catch (Exception e) {
			logger.error("查询交易跟踪失败", e);
			result.setFailMessage("查询交易跟踪列表失败");
		}
		return result;

	}
	
	@Override
	public PerformanceResult tradeAllType(String appId,String type, String agentId, String keyWord, String transactionType, long startDate,
			long endDate, String orderBy, boolean desc, int pageSize, int pageIndex) {
		long startTime1 = System.currentTimeMillis();
		PerformanceResult result = new PerformanceResult();
		if ("NaN".equals(endDate) || "NaN".equals(startDate)) {
			result.setFailMessage("查询时间错误");
			return result;
		}
		if (StringUtils.isBlank(agentId) || StringUtils.isBlank(appId)) {
			result.setFailMessage("参数错误");
			return result;
		}
		//默认一小时
		if (endDate == 0)
			endDate = System.currentTimeMillis();
		if (startDate == 0)
			startDate = endDate - 60 * 60 * 1000;
		List<TradePerformance> perfs = new ArrayList<TradePerformance>();
		List<PerformanceView> typePerfs = new ArrayList<PerformanceView>();
		try {
			long startTime = System.currentTimeMillis();
			perfs = tradePerformanceLogic.tradeAllType(appId, agentId,type,keyWord, orderBy, desc, new Date(startDate), new Date(endDate), 100);
			logger.info("交易类型ES查询耗时：" + (System.currentTimeMillis() - startTime));
			if(StringUtils.isBlank(orderBy)){
				orderBy = "business/error/count";   // 默认按错误数
			}
			List<OrderClass> orders = new ArrayList<OrderClass>();
			for (PerformanceView perf : typePerfs) {
				PerformanceView perfView = new PerformanceView();
				perfView.setApplicationId(appId);
				perfView.setServiceId(agentId);
				perfView.setResourceId(perf.get("resourceId").toString());
				perfView.setTransactionTypeName(perf.get("typeName").toString());
				perfView.put("business/error/count", perf.get("isError"));
				perfView.put("business/throughput/total", perf.get("count"));
				perfView.put("business/response_time/avg", perf.get("responseTime"));
				perfView.put("business/success/rate",
						Double.parseDouble(perf.get("count").toString()) == 0 ? "-"
								: new DecimalFormat("0.00").format(100
										* (Double.parseDouble(perf.get("count").toString())
												- Double.parseDouble(perf.get("isError").toString()))
										/ Double.parseDouble(perf.get("count").toString())));
				OrderClass clazz = new OrderClass();
				clazz.setPerformanceView(perfView);
				clazz.setOrder(Double.valueOf(perfView.get(orderBy).toString()));
				orders.add(clazz);
			}
			startTime = System.currentTimeMillis();
			if(orders != null && orders.size() > 0){
				if(orderBy.equals("business/error/count")){              // 错误数升序
					Collections.sort(orders, new Comparator<OrderClass>() {
						@Override
						public int compare(OrderClass o1, OrderClass o2) {
							return o1.getOrder().compareTo(o2.getOrder()) ;
						}
					});
				}else if(orderBy.equals("business/throughput/total")){   // 吞吐量降序
					Collections.sort(orders, new Comparator<OrderClass>() {
						@Override
						public int compare(OrderClass o1, OrderClass o2) {
							return o2.getOrder().compareTo(o1.getOrder());
						}
					});
				}else if(orderBy.equals("business/response_time/avg")){   // 平均响应时间升序
					Collections.sort(orders, new Comparator<OrderClass>() {
						@Override
						public int compare(OrderClass o1, OrderClass o2) {
							return o1.getOrder().compareTo(o2.getOrder());
						}
					});
				}else if(orderBy.equals("business/success/rate")){        // 成功率降序
					Collections.sort(orders, new Comparator<OrderClass>() {
						@Override
						public int compare(OrderClass o1, OrderClass o2) {
							return o2.getOrder().compareTo(o1.getOrder());
						}
					});
				}
				for(OrderClass clazz:orders){
					PerformanceView perf = clazz.getPerformanceView();
					TradePerformance tradePerf = new TradePerformance(perf.getTransactionTypeName(), perf.getResourceId(), null, null, 0, perf);
					perfs.add(tradePerf);
				}
			}
			logger.info("交易类型排序耗时" + (System.currentTimeMillis() - startTime));
			result.pagingHandle(pageSize > 0 ? pageSize : 10, pageIndex, perfs);
		} catch (Exception e) {
			result.setFailMessage("查询性能数据失败");
		}
		logger.info("交易类型总耗时：" + (System.currentTimeMillis() - startTime1));
		return result;
	}
	
	@SuppressWarnings("unused")
	@Override
	public PerformanceResult downloadTransactionType(HttpServletRequest request, HttpServletResponse response, String appId, String serviceId, String keyWord, String tran, String name, String orderBy, boolean desc, long startDate, long endDate) throws Exception {
		PerformanceResult result = new PerformanceResult();
		//TODO 下载报表需要修改
		if ("NaN".equals(endDate) || "NaN".equals(startDate)) {
			result.setFailMessage("查询时间错误");
			return result;
		}
		if (StringUtils.isBlank(serviceId)) {
			return null;
		}
        OutputStream outPut = response.getOutputStream();
        try {
        	response.setContentType("application/vnd.ms-excel;charset=UTF-8");
        	String filename = URLEncoder.encode("交易类型.xls", "UTF-8");
        	if("FF".equals(getBrowser(request))){
        		response.setContentType("application/vnd.ms-excel;charset=ISO-8859-1");
        		filename = new String(filename.getBytes("UTF-8"),"ISO-8859-1");
        	}
            response.setHeader("Content-Disposition", "attachment; filename=" + filename + ";filename*=UTF-8''" + filename);
            
//			List<TradePerformance> dataList = tradePerformanceLogic.tradeAllType(appId, serviceId, keyWord, orderBy, desc,
//					new Date(startDate), new Date(endDate), 100);
            List<PerformanceView> typePerfs = null;
            List<TradePerformance> tradePerfs = null;
            Service service = serverLogic.queryServiceById(serviceId);
            if(service == null){
				result.setFailMessage("该服务节点不存在");
				return result;
			}
			if (service != null && service.getNodeType() == 2) {
				tradePerfs = tradePerformanceLogic.tradeAllType(appId, serviceId,"", keyWord, orderBy, desc, new Date(startDate), new Date(endDate), 100);
			} else {
//				typePerfs = tradePerformanceLogic.getChannelByType(appId, serviceId, keyWord, null,
//						new Date(startDate - 60 * 1000), new Date(endDate - 60 * 1000), "typeName", orderBy, desc, 100);
			}
			List<TradePerformance> dataList = new ArrayList<TradePerformance>();
			if(typePerfs != null && typePerfs.size() > 0){
				for (PerformanceView perf : typePerfs) {
					PerformanceView perfView = new PerformanceView();
					perfView.setApplicationId(appId);
					perfView.setServiceId(serviceId);
					perfView.setResourceId(perf.get("resourceId").toString());
					perfView.setTransactionTypeName(perf.get("typeName").toString());
					perfView.put("business/error/count", perf.get("isError"));
					perfView.put("business/throughput/total", perf.get("count"));
					perfView.put("business/response_time/avg", perf.get("responseTime"));
					perfView.put("business/success/rate",
							Double.parseDouble(perf.get("count").toString()) == 0 ? "-"
									: new DecimalFormat("0.00").format(100 * (Double.parseDouble(perf.get("count").toString())
											- Double.parseDouble(perf.get("isError").toString()))
											/ Double.parseDouble(perf.get("count").toString())));
					perfView.put("business/apdex/rate",
							(perf.get("count") == null
							|| Double.parseDouble(perf.get("count").toString()) == 0)
							? "0.0"
									: new DecimalFormat("0.00").format(100 * ((Double
											.parseDouble(perf.get("apdexFlag_satisfaction").toString())
											+ Double.parseDouble(perf.get("apdexFlag_tolerate").toString()) * 0.5)
											/ Double.parseDouble(perf.get("count").toString()))));
					TradePerformance tradePerf = new TradePerformance(perf.get("typeName").toString(),
							perf.get("resourceId").toString(), null, null, 0, perfView);
					dataList.add(tradePerf);
				}
			}
			if(tradePerfs != null && tradePerfs.size() > 0){
				for(TradePerformance trade : tradePerfs){
					PerformanceView perf = trade.getPerformance();
					PerformanceView perfView = new PerformanceView();
					perfView.setApplicationId(appId);
					perfView.setServiceId(serviceId);
					perfView.setResourceId(perf.get("resourceId").toString());
					perfView.setTransactionTypeName(perf.get("transactionTypeName").toString());
					perfView.put("business/error/count", perf.get("business/error/count"));
					perfView.put("business/throughput/total", perf.get("business/throughput/total"));
					perfView.put("business/response_time/avg", perf.get("business/response_time/avg"));
					perfView.put("business/success/rate", perf.get("business/success/rate"));
					perfView.put("business/apdex/rate", perf.get("business/apdex/rate"));
					TradePerformance tradePerf = new TradePerformance(perf.get("transactionTypeName").toString(),
							perf.get("resourceId").toString(), null, null, 0, perfView);
					dataList.add(tradePerf);
				}
			}
			
			HSSFWorkbook wb = new HSSFWorkbook();  
			HSSFSheet sheet = wb.createSheet("交易类型");

			sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 5));
			Cell cell = sheet.createRow((int) 0).createCell(0);
			cell.setCellValue(service.getName() + "服务节点交易类型");
			cell.setCellStyle(createCellStyle(wb, 1));

			sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, 5));
			Cell cellt = sheet.createRow((int) 1).createCell(0);
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd");
			cellt.setCellValue(sdf.format(new Date(startDate)) + "-" + sdf.format(new Date(endDate)));
			cellt.setCellStyle(createCellStyle(wb, 2));

			createTradeHead(sheet, 2, createCellStyle(wb, 3), "交易类型");
			createTradeContent(sheet, 3, createCellStyle(wb, 4), dataList);
			wb.write(outPut);
			outPut.close();
        } catch (Exception e) {
        	ExceptionUtils.error(logger, "导出交易类型表格出错", e);
        	result.setFailMessage("导出交易类型表格出错");
        }
		return result;
	}
	
	@Override
	public PerformanceResult downloadTransactionChannel(HttpServletRequest request,HttpServletResponse response,
			String appId, String serviceId, String keyWord,
			String transactionChannel, String orderBy, 
			boolean desc, long startDate, long endDate) throws Exception{
		//TODO 下载报表需要修改
		PerformanceResult result = new PerformanceResult();
		if ("NaN".equals(endDate) || "NaN".equals(startDate)) {
			result.setFailMessage("查询时间错误");
			return result;
		}
		if (StringUtils.isBlank(serviceId)) {
			return null;
		}
        OutputStream outPut = response.getOutputStream();
        try {
        	response.setContentType("application/vnd.ms-excel;charset=UTF-8");
        	String filename = URLEncoder.encode("交易渠道.xls", "UTF-8");
        	if("FF".equals(getBrowser(request))){
        		response.setContentType("application/vnd.ms-excel;charset=ISO-8859-1");
        		filename = new String(filename.getBytes("UTF-8"),"ISO-8859-1");
        	}
            response.setHeader("Content-Disposition", "attachment; filename=" + filename + ";filename*=UTF-8''" + filename);
//			List<TradePerformance> dataList = tradePerformanceLogic.tradeAllChannel(appId, serviceId, keyWord, transactionChannel, orderBy, desc, new Date(startDate), new Date(endDate), 100);
			List<TradePerformance> dataList = new ArrayList<TradePerformance>();
//			List<PerformanceView> typePerfs = tradePerformanceLogic.getChannelByType(appId, serviceId, keyWord, null,
//					new Date(startDate - 60 * 1000), new Date(endDate - 60 * 1000), "channelName", orderBy, desc, 100);
//			for (PerformanceView perf : typePerfs) {
//				PerformanceView perfView = new PerformanceView();
//				perfView.setApplicationId(appId);
//				perfView.setServiceId(serviceId);
//				perfView.setResourceId(perf.get("resourceId").toString());
//				perfView.setTransactionChannelName(perf.get("channelName").toString());
//				perfView.put("business/error/count", perf.get("isError"));
//				perfView.put("business/throughput/total", perf.get("count"));
//				perfView.put("business/response_time/avg", perf.get("responseTime"));
//				perfView.put("business/success/rate",
//						Double.parseDouble(perf.get("count").toString()) == 0 ? "-"
//								: new DecimalFormat("0.00").format(100 * (Double.parseDouble(perf.get("count").toString())
//										- Double.parseDouble(perf.get("isError").toString()))
//										/ Double.parseDouble(perf.get("count").toString())));
//				perfView.put("business/apdex/rate",
//						(perf.get("count") == null
//								|| Double.parseDouble(perf.get("count").toString()) == 0)
//										? "0.0"
//										: new DecimalFormat("0.00").format(100 * ((Double
//												.parseDouble(perf.get("apdexFlag_satisfaction").toString())
//												+ Double.parseDouble(perf.get("apdexFlag_tolerate").toString()) * 0.5)
//												/ Double.parseDouble(perf.get("count").toString()))));
//				TradePerformance tradePerf = new TradePerformance(perf.get("typeName").toString(),
//						perf.get("resourceId").toString(), null, null, 0, perfView);
//				dataList.add(tradePerf);
//			}
			Service service = serverLogic.queryServiceById(serviceId);
			if(service == null){
				result.setFailMessage("该服务节点不存在");
				return result;
			}
			HSSFWorkbook wb = new HSSFWorkbook();  
			HSSFSheet sheet = wb.createSheet("交易渠道");

			sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 5));
			Cell cell = sheet.createRow((int) 0).createCell(0);
			cell.setCellValue(service.getName() + "交易渠道");
			cell.setCellStyle(createCellStyle(wb, 1));

			sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, 5));
			Cell cellt = sheet.createRow((int) 1).createCell(0);
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd");
			cellt.setCellValue(sdf.format(new Date(startDate)) + "-" + sdf.format(new Date(endDate)));
			cellt.setCellStyle(createCellStyle(wb, 2));
	        
			createTradeHead(sheet, 2, createCellStyle(wb, 3), "交易渠道");
			createTradeContent(sheet, 3, createCellStyle(wb, 4), dataList);
			wb.write(outPut);
			outPut.close();
        } catch (Exception e) {
        	ExceptionUtils.error(logger, "导出交易渠道表格出错", e);
        	result.setFailMessage("导出交易渠道表格出错");
        }
		return result;
	}

	@Override
	public PerformanceResult multiStatistic(String agentId, String transactionType, String transactionChannel,
			String dstIp, String srcIp, String responseCode, String keyWord, long startDate,
			long endDate, String orderBy, boolean desc, String groupBy, int pageSize, int pageIndex) throws Exception {
		PerformanceResult result = new PerformanceResult();
		if ("NaN".equals(endDate) || "NaN".equals(startDate)) {
			result.setFailMessage("查询时间错误");
			return result;
		}
		if (StringUtils.isBlank(agentId) || StringUtils.isBlank(groupBy)) {
			result.setFailMessage("参数错误");
			return result;
		}
		if (endDate == 0)
			endDate = System.currentTimeMillis();
		if (startDate == 0)
			startDate = endDate - 60 * 60 * 1000;
		
		int dimension = 1;
		if(StringUtils.isNotBlank(transactionType)){
			dimension ++;
		}
		if(StringUtils.isNotBlank(transactionChannel)){
			dimension ++;
		}
		if(StringUtils.isNotBlank(dstIp)){
			dimension ++;
		}
		if(StringUtils.isNotBlank(srcIp)){
			dimension ++;
		}
		if(StringUtils.isNotBlank(responseCode)){
			dimension ++;
		}
		result.put("dimension", dimension);
		
		// 从MySQL查询同一应用系统下所有的节点
		Set<String> agentIds = new HashSet<String>();
		List<PerformanceView> perfs = new ArrayList<PerformanceView>();
		try {
			// 查询出所有的数据
			perfs = tradePerformanceLogic.getMultiStatistics(agentIds,
					keyWord, transactionType, transactionChannel, dstIp, srcIp, responseCode, startDate, endDate, orderBy, groupBy, desc);
			//分页
			List<PerformanceView> list = null;
			if(pageSize == 1){   // 全部返回
				list = perfs;
			}else{
				if(perfs != null && perfs.size() > 0){
					if(perfs.size() > pageSize){
						list = perfs.subList(0, pageSize);
					}else{
						list = perfs;
					}
				}
			}
			result.put("result", list);    // top
			perfs = null;
		}catch(Exception e){
			ExceptionUtils.error(logger, "查询性能数据出错", e);
        	result.setFailMessage("查询性能数据出错");
		}
		return result;
	}

	@Override
	public Result transactionDetail(String spanId, long startDate, long endDate) throws Exception {
		PerformanceResult result = new PerformanceResult();
		if ("NaN".equals(endDate) || "NaN".equals(startDate)) {
			result.setFailMessage("查询时间错误");
			return result;
		}
		if (StringUtils.isBlank(spanId)) {
			result.setFailMessage("参数错误");
			return result;
		}
		if (endDate == 0)
			endDate = System.currentTimeMillis();
		if (startDate == 0)
			startDate = endDate - 60 * 60 * 1000;
		try{
			List<PerformanceView> list = new ArrayList<PerformanceView>();
			list.add(tradePerformanceLogic.transactionDetail(spanId, startDate, endDate));
			result.setPerformances(list);
		} catch(Exception e){
			ExceptionUtils.error(logger, "查询交易原始数据出错", e);
        	result.setFailMessage("查询交易原始数据出错");
		}
		return result;
	}

	@Override
	public PerformanceResult downloadMultiStatistic(String appId, HttpServletRequest request,
			HttpServletResponse response, String transactionType, String transactionChannel, String dstIp, String srcIp,
			String responseCode, String serviceId, String keyWord, long startDate, long endDate, String orderBy,
			boolean desc, String groupBy, int pageSize, int pageIndex) throws Exception {
		PerformanceResult result = new PerformanceResult();
		if ("NaN".equals(endDate) || "NaN".equals(startDate)) {
			result.setFailMessage("查询时间错误");
			return result;
		}
		if (StringUtils.isBlank(appId)) {
			result.setFailMessage("参数错误");
			return result;
		}
        OutputStream outPut = response.getOutputStream();
        try {
        	response.setContentType("application/vnd.ms-excel;charset=UTF-8");
        	String filename = URLEncoder.encode("多维统计.xls", "UTF-8");
        	if("FF".equals(getBrowser(request))){
        		response.setContentType("application/vnd.ms-excel;charset=ISO-8859-1");
        		filename = new String(filename.getBytes("UTF-8"),"ISO-8859-1");
        	}
            response.setHeader("Content-Disposition", "attachment; filename=" + filename + ";filename*=UTF-8''" + filename);
			if(StringUtils.isBlank(groupBy)){
				result.setFailMessage("分组字段不能为空！");
				return result;
			}
			
			// 从MySQL查询同一应用系统下所有的节点
			Set<String> agentIds = new HashSet<String>();
			List<PerformanceView> dataList = tradePerformanceLogic.getMultiStatistics(agentIds, keyWord,
					transactionType, transactionChannel, dstIp, srcIp, responseCode, startDate, endDate, orderBy,
					groupBy, desc);
			// 统计也分top
			List<PerformanceView> list = null;
			if(pageSize == 1){   // 全部返回
				list = dataList;
			}else{
				if(dataList != null && dataList.size() > 0){
					if(dataList.size() > pageSize){
						list = dataList.subList(0, pageSize);
					} else{
						list = dataList;
					}
				}
			}
			dataList = null;
			ApplicationSystem app = appLogic.getApplicationById(appId);
			if(app == null){
				result.setFailMessage("该应用系统不存在");
				return result;
			}
			HSSFWorkbook wb = new HSSFWorkbook();  
			HSSFSheet sheet = wb.createSheet(app.getName());

			sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 3));
			Cell cell = sheet.createRow((int) 0).createCell(0);
			cell.setCellValue(app.getName() + "多维统计");
			cell.setCellStyle(createCellStyle(wb, 1));

			sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, 3));
			Cell cellt = sheet.createRow((int) 1).createCell(0);
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd");
			cellt.setCellValue(sdf.format(new Date(startDate)) + "-" + sdf.format(new Date(endDate)));
			cellt.setCellStyle(createCellStyle(wb, 2));
			
			sheet.addMergedRegion(new CellRangeAddress(2, 2, 0, 3));
			Cell cellD = sheet.createRow((int) 2).createCell(0);
			
			int dimension = 1;
			if(StringUtils.isNotBlank(transactionType)){
				dimension ++;
			}
			if(StringUtils.isNotBlank(transactionChannel)){
				dimension ++;
			}
			if(StringUtils.isNotBlank(dstIp)){
				dimension ++;
			}
			if(StringUtils.isNotBlank(srcIp)){
				dimension ++;
			}
			if(StringUtils.isNotBlank(responseCode)){
				dimension ++;
			}
			StringBuffer sb = new StringBuffer();
			if(StringUtils.isNotBlank(transactionType)){
				sb.append(" 交易类型：").append(transactionType);
			}if(StringUtils.isNotBlank(transactionChannel)){
				sb.append(" 交易渠道：").append(transactionChannel);
			}if(StringUtils.isNotBlank(responseCode)){
				sb.append(" 返回码：").append(responseCode);
			}if(StringUtils.isNotBlank(dstIp)){
				sb.append(" 服务端IP：").append(dstIp);
			}if(StringUtils.isNotBlank(srcIp)){
				sb.append(" 客户端IP：").append(srcIp);
			}
			String dimensionStr = "第" + dimension + "维度：" + sb.toString();
			cellD.setCellValue(dimensionStr);
			cellD.setCellStyle(createCellStyle(wb, 7));
	        
			createMultiStatisticHead(sheet, 3, createCellStyle(wb, 3), groupBy);
			if(list != null && !list.isEmpty()){
				createMultiStatisticContent(sheet, 4, createCellStyle(wb, 4), list, groupBy);
            }
			wb.write(outPut);
			outPut.close();
        } catch (Exception e) {
        	ExceptionUtils.error(logger, "导出多维统计表格出错", e);
        	result.setFailMessage("导出多维统计表格出错");
        }
		return result;
	}

	// 以下为服务器端判断客户端浏览器类型的方法  
    private String getBrowser(HttpServletRequest request) {  
        String UserAgent = request.getHeader("USER-AGENT").toLowerCase();  
        if (UserAgent != null) {  
            if (UserAgent.indexOf("msie") >= 0)  
                return "IE";  
            if (UserAgent.indexOf("firefox") >= 0)  
                return "FF";  
            if (UserAgent.indexOf("safari") >= 0)  
                return "SF";  
        }  
        return null;  
    }

	
	/**
	 * 生成单元格样式
	 * @param wb
	 * @param type
	 * @return
	 */
	private HSSFCellStyle createCellStyle(HSSFWorkbook wb, int type){
		HSSFCellStyle style = null;
		switch(type){
			case 1 :
				// 设置标题样式  
				style = wb.createCellStyle();  
				Font fontTitle = wb.createFont();  
				fontTitle.setBoldweight(Font.BOLDWEIGHT_BOLD); // 粗体  
				fontTitle.setFontHeightInPoints((short)20);
				fontTitle.setFontName("黑体");
				style.setFont(fontTitle);  
				style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 水平居中  
				style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中;
				break;
			case 2 : 
				// 设置时间样式  
				style = wb.createCellStyle();  
				Font fontTime = wb.createFont();  
				fontTime.setBoldweight(Font.BOLDWEIGHT_BOLD); // 粗体  
				fontTime.setFontHeightInPoints((short)17);
				style.setFont(fontTime);
				style.setAlignment(HSSFCellStyle.ALIGN_RIGHT); // 水平居右 
				style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中
				break;
			case 3 :
				// 设置列名样式  
				style = wb.createCellStyle();  
				style.setWrapText(true);
				style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
				style.setBorderRight(HSSFCellStyle.BORDER_THIN);
				style.setBorderTop(HSSFCellStyle.BORDER_THIN);
				style.setBorderBottom(HSSFCellStyle.BORDER_THIN);  
				Font font_col = wb.createFont();  
				font_col.setBoldweight(Font.BOLDWEIGHT_BOLD); // 粗体  
				font_col.setFontHeightInPoints((short)12);
				style.setFont(font_col);
				style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 水平居中  
				style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中
				break;
			case 5 : 
				style = wb.createCellStyle();
				style.setWrapText(true);
				style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
				style.setBorderRight(HSSFCellStyle.BORDER_THIN);
				style.setBorderTop(HSSFCellStyle.BORDER_THIN);
				style.setBorderBottom(HSSFCellStyle.BORDER_THIN);  
				Font font_title = wb.createFont();  
				font_title.setFontHeightInPoints((short)12);
				style.setFont(font_title);
				style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 水平居中
				style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中
				break;
			case 6 : 
				style = wb.createCellStyle();
				style.setWrapText(true);
				style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
				style.setBorderRight(HSSFCellStyle.BORDER_THIN);
				style.setBorderTop(HSSFCellStyle.BORDER_THIN);
				style.setBorderBottom(HSSFCellStyle.BORDER_THIN);  
				Font _title = wb.createFont();  
				_title.setFontHeightInPoints((short)12);
				style.setFont(_title);
				style.setAlignment(HSSFCellStyle.ALIGN_LEFT); // 水平居左
				style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中
				break;
			case 7 : 
				style = wb.createCellStyle();
				Font title = wb.createFont();  
				title.setFontHeightInPoints((short)12);
				style.setFont(title);
				style.setAlignment(HSSFCellStyle.ALIGN_LEFT); // 水平居左
				style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中
				break;
			default :
				style = wb.createCellStyle();
				style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
				style.setBorderRight(HSSFCellStyle.BORDER_THIN);
				style.setBorderTop(HSSFCellStyle.BORDER_THIN);
				style.setBorderBottom(HSSFCellStyle.BORDER_THIN);  
				Font font_content = wb.createFont();  
				font_content.setFontHeightInPoints((short)12);
				style.setFont(font_content);
				style.setAlignment(HSSFCellStyle.ALIGN_RIGHT); // 水平居右
				style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中
		}
		return style;
	}
	
	/**
	 * 生成交易类型/交易渠道表头
	 * @param sheet
	 * @param startRow
	 * @param createCellStyle
	 * @param channel   交易类型/交易渠道
	 */
	private void createTradeHead(HSSFSheet sheet, int startRow, HSSFCellStyle createCellStyle, String channel){
		int index = 0;
		Row row = sheet.createRow(startRow);
		row.setHeightInPoints(45);
		Cell cell_1 = row.createCell(0);
		cell_1.setCellValue(channel);
		index = sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, 0, 0));
		CellRangeAddress range0 = sheet.getMergedRegion(index);
		setRegionStyle(sheet, range0, createCellStyle);
		sheet.setColumnWidth(0, 4000); 
		Cell cell_2 = row.createCell(1);
		cell_2.setCellValue("Apdex");
		index = sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, 1, 1));
		CellRangeAddress range1 = sheet.getMergedRegion(index);
		setRegionStyle(sheet, range1, createCellStyle);
		sheet.setColumnWidth(1, 4000);
		Cell cell_3 = row.createCell(2);
		cell_3.setCellValue("交易量");
		index = sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, 2, 2));
		CellRangeAddress range2 = sheet.getMergedRegion(index);
		setRegionStyle(sheet, range2, createCellStyle);
		sheet.setColumnWidth(2, 4000);
		Cell cell_4 = row.createCell(3);
		cell_4.setCellValue("平均响应时间（ms）");
		index = sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, 3, 3));
		CellRangeAddress range3 = sheet.getMergedRegion(index);
		setRegionStyle(sheet, range3, createCellStyle);
		sheet.setColumnWidth(3, 4000);
		Cell cell_5 = row.createCell(4);
		cell_5.setCellValue("成功率（%）");
		index = sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, 4, 4));
		CellRangeAddress range4 = sheet.getMergedRegion(index);
		setRegionStyle(sheet, range4, createCellStyle);
		sheet.setColumnWidth(4, 4000);
		Cell cell_6 = row.createCell(5);
		cell_6.setCellValue("错误数");
		index = sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, 5, 5));
		CellRangeAddress range5 = sheet.getMergedRegion(index);
		setRegionStyle(sheet, range5, createCellStyle);
		sheet.setColumnWidth(5, 4000);
	}
	
	/**
	 * 生成交易类型/交易渠道内容
	 * @param sheet
	 * @param startRow
	 * @param createCellStyle
	 * @param list
	 */
	private void createTradeContent(HSSFSheet sheet, int startRow, HSSFCellStyle createCellStyle,List<TradePerformance> list){
		int index = 0 ;
		if(list != null && list.size() > 0){
			int size = list.size();
			HSSFCellStyle style = createCellStyle(sheet.getWorkbook(), 6);
			for(int i=0; i<size; i++){
				PerformanceView pv = list.get(i).getPerformance();
				String name = list.get(i).getName();
				Row row = sheet.createRow(startRow);
				row.setHeightInPoints(18);
				Cell cell_0 = row.createCell(0);
				cell_0.setCellValue(name);
				index = sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, 0, 0));
				CellRangeAddress range0 = sheet.getMergedRegion(index);
				setRegionStyle(sheet, range0, style);
				Cell cell_1 = row.createCell(1);
				cell_1.setCellValue(pv.get("business/apdex/rate").toString() == null ? "-" :pv.get("business/apdex/rate").toString().equals("-") ? "-"
						: String.valueOf(new BigDecimal(pv.get("business/apdex/rate").toString()).setScale(2, BigDecimal.ROUND_DOWN).doubleValue()));
				index = sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, 1, 1));
				CellRangeAddress range1 = sheet.getMergedRegion(index);
				setRegionStyle(sheet, range1, createCellStyle);
				Cell cell_2 = row.createCell(2);
				cell_2.setCellValue(pv.get("business/throughput/total") == null ? "-" : (long)Double.parseDouble(pv.get("business/throughput/total").toString())+"");
				index = sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, 2, 2));
				CellRangeAddress range2 = sheet.getMergedRegion(index);
				setRegionStyle(sheet, range2, createCellStyle);
				Cell cell_3 = row.createCell(3);
				cell_3.setCellValue(pv.get("business/response_time/avg") == null ? "-" : pv.get("business/throughput/total").toString().equals("-")? "-"
						: String.valueOf(new BigDecimal((Double)pv.get("business/response_time/avg")/1000.0).setScale(2, BigDecimal.ROUND_DOWN).doubleValue()));
				index = sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, 3, 3));
				CellRangeAddress range3 = sheet.getMergedRegion(index);
				setRegionStyle(sheet, range3, createCellStyle);
				Cell cell_4 = row.createCell(4);
				cell_4.setCellValue(pv.get("business/success/rate") == null ? "-" : pv.get("business/success/rate").toString().equals("-")? "-":
					String.valueOf(new BigDecimal(pv.get("business/success/rate").toString()).setScale(2, BigDecimal.ROUND_DOWN).doubleValue()));
				index = sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, 4, 4));
				CellRangeAddress range4 = sheet.getMergedRegion(index);
				setRegionStyle(sheet, range4, createCellStyle);
				Cell cell_5 = row.createCell(5);
				cell_5.setCellValue(pv.get("business/error/count") == null ? "-" : (long)Double.parseDouble(pv.get("business/error/count").toString()) + "");
				index = sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, 5, 5));
				CellRangeAddress range5 = sheet.getMergedRegion(index);
				setRegionStyle(sheet, range5, createCellStyle);
				startRow ++ ;
			}
		}
	}
	
	/**
	 * 创建多维统计表头
	 * @param sheet
	 * @param startRow
	 * @param createCellStyle
	 * @param groupBy
	 */
	private void createMultiStatisticHead(HSSFSheet sheet, int startRow, HSSFCellStyle createCellStyle, String groupBy){
		int index = 0;
		Row row = sheet.createRow(startRow);
		row.setHeightInPoints(20);
		Cell cell_0 = row.createCell(0);
		if(groupBy.equals("typeName")){
			groupBy = "交易类型";
		} else if(groupBy.equals("channelName")){
			groupBy = "交易渠道";
		} else if(groupBy.equals("responseCode")){
			groupBy = "交易返回码";
		} else if(groupBy.equals("dstIp")){
			groupBy = "服务器IP";
		} else if(groupBy.equals("srcIp")){
			groupBy = "客户端IP";
		}
		cell_0.setCellValue(groupBy);
		index = sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, 0, 0));
		CellRangeAddress range0 = sheet.getMergedRegion(index);
		setRegionStyle(sheet, range0, createCellStyle);
		sheet.setColumnWidth(0, 4000); 
		Cell cell_1 = row.createCell(1);
		cell_1.setCellValue("交易笔数");
		index = sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, 1, 1));
		CellRangeAddress range1 = sheet.getMergedRegion(index);
		setRegionStyle(sheet, range1, createCellStyle);
		sheet.setColumnWidth(1, 4000); 
		Cell cell_2 = row.createCell(2);
		cell_2.setCellValue("交易成功率(%)");
		index = sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, 2, 2));
		CellRangeAddress range2 = sheet.getMergedRegion(index);
		setRegionStyle(sheet, range2, createCellStyle);
		sheet.setColumnWidth(2, 4000); 
		Cell cell_3 = row.createCell(3);
		cell_3.setCellValue("响应时间(ms)");
		index = sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, 3, 3));
		CellRangeAddress range3 = sheet.getMergedRegion(index);
		setRegionStyle(sheet, range3, createCellStyle);
		sheet.setColumnWidth(3, 4000); 
	}
	
	/**
	 * 创建多维统计内容
	 * @param sheet
	 * @param startRow
	 * @param createCellStyle
	 * @param list
	 */
	private void createMultiStatisticContent(HSSFSheet sheet, int startRow, HSSFCellStyle createCellStyle, List<PerformanceView> list, String groupBy){
		int index = 0;
		if(list != null && list.size() > 0){
			HSSFCellStyle style = createCellStyle(sheet.getWorkbook(), 6);
			for(PerformanceView pv : list){
				Row row = sheet.createRow(startRow);
				row.setHeightInPoints(44);
				Cell cell_0 = row.createCell(0);
				cell_0.setCellValue(pv.get(groupBy).toString());
				style.setWrapText(true);
				index = sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, 0, 0));
				CellRangeAddress range0 = sheet.getMergedRegion(index);
				setRegionStyle(sheet, range0, style);
				Cell cell_1 = row.createCell(1);
				cell_1.setCellValue((long)Double.parseDouble(pv.get("business/throughput/total").toString()) + "");
				index = sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, 1, 1));
				CellRangeAddress range1 = sheet.getMergedRegion(index);
				setRegionStyle(sheet, range1, createCellStyle);
				Cell cell_2 = row.createCell(2);
				cell_2.setCellValue(pv.get("business/success/rate").toString());
				index = sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, 2, 2));
				CellRangeAddress range2 = sheet.getMergedRegion(index);
				setRegionStyle(sheet, range2, createCellStyle);
				Cell cell_3 = row.createCell(3);
				cell_3.setCellValue(String.valueOf(new BigDecimal(Double.valueOf(pv.get("business/response_time/avg").toString())/ 1000).setScale(2, BigDecimal.ROUND_DOWN).doubleValue()).toString());
				index = sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, 3, 3));
				CellRangeAddress range3 = sheet.getMergedRegion(index);
				setRegionStyle(sheet, range3, createCellStyle);
				startRow ++;
			}
		}
	}
	
	/**
	 * 合并单元格带边框
	 * @param sheet
	 * @param region
	 * @param cs
	 */
	private static void setRegionStyle(HSSFSheet sheet, CellRangeAddress region , HSSFCellStyle cs) {
		for (int i = region.getFirstRow() ; i <= region.getLastRow(); i ++) {
			HSSFRow row = sheet.getRow(i);
			if(row == null){
				row = sheet.createRow(i);
			}
			for (int j = region.getFirstColumn(); j <= region.getLastColumn(); j++) {
				Cell cell = row.getCell(j);
				if(cell == null){
					cell = row.createCell(j);
					cell.setCellValue(" ");
				}
				cell.setCellStyle(cs);
			}
		}
	}
	
	@Override
	public TransactionResult queryTransactionChannel(String appId) {
		TransactionResult result = new TransactionResult();
		List<TransactionChannel> transactionList = transactionLogic.getTransactionChannelByAppId(appId);
		result.setTransactionChannel(transactionList);
		return result;
	}

	@Override
	public TransactionResult queryTransactionType(String appId) {
		TransactionResult result = new TransactionResult();
		List<TransactionType> transactionList = transactionLogic.getTransactionTypeByAppId(appId);
		result.setTransactionType(transactionList);
		return result;
	}
}
